package cn.lili.modules.order.cart.render.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.CurrencyUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.goods.client.CategoryClient;
import cn.lili.modules.goods.client.GoodsClient;
import cn.lili.modules.goods.entity.dos.Category;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dos.Wholesale;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsMarketEnum;
import cn.lili.modules.goods.entity.enums.SalesModeEnum;
import cn.lili.modules.member.client.RedPackUserClient;
import cn.lili.modules.member.entity.dos.RedPackUser;
import cn.lili.modules.order.cart.entity.dto.TradeDTO;
import cn.lili.modules.order.cart.entity.enums.DeliveryMethodEnum;
import cn.lili.modules.order.cart.entity.enums.RenderStepEnums;
import cn.lili.modules.order.cart.entity.vo.CartSkuVO;
import cn.lili.modules.order.cart.entity.vo.CartVO;
import cn.lili.modules.order.cart.render.CartRenderStep;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.dto.PriceDetailDTO;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.payment.client.WalletPointClient;
import cn.lili.modules.promotion.client.BoxMhGoodsClient;
import cn.lili.modules.promotion.client.PromotionGoodsClient;
import cn.lili.modules.promotion.entity.dos.*;
import cn.lili.modules.promotion.entity.vos.CouponVO;
import cn.lili.modules.system.constants.DictConstant;
import cn.lili.util.GoodsSkuPriceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品有效性校验 && 第一次更具逻辑中的店铺进行拆单
 *
 * @author Chopper
 * @since 2020-07-02 14:47
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CheckDataRender implements CartRenderStep {

    private final GoodsClient goodsClient;

    private final OrderService orderService;

    private final PromotionGoodsClient promotionGoodsClient;

    private final CategoryClient categoryClient;

    private final WalletPointClient walletPointClient;

    private final BoxMhGoodsClient boxMhGoodsClient;

    private final RedPackUserClient redPackUserClient;


    @Override
    public RenderStepEnums step() {
        return RenderStepEnums.CHECK_DATA;
    }

    @Override
    public void render(TradeDTO tradeDTO) {

        //加个第一次处理
        prePrice(tradeDTO);

        //预校验
        preCalibration(tradeDTO);

        //校验商品有效性
        checkData(tradeDTO);

        //销售模式处理
        preSaleModel(tradeDTO);
        //店铺分组数据初始化
        groupStore(tradeDTO);

        //设置分类信息，以及分类佣金比例信息
        setCategoryInformation(tradeDTO);
    }

    /**
     * 预校验
     *
     * @param tradeDTO
     */
    private void prePrice(TradeDTO tradeDTO) {
        long buyerIdMh = orderService.count(new LambdaQueryWrapper<Order>().eq(Order::getBuyerId, UserContext.getCurrentId()).isNotNull(Order::getMhId));
        for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) {
            //是否盲盒商品 && 没有购买过盲盒  && 是新人盲盒活动  == 第一次取新人价 + 购买三件（ 3 - 1） *  单价
            if (StringUtils.isNotEmpty(cartSkuVO.getGoodsSku().getMhId()) && buyerIdMh == 0L) {
                BoxMhgoods boxMhgoods = boxMhGoodsClient.getById(cartSkuVO.getGoodsSku().getMhId());
                if (boxMhgoods != null && DictConstant.YES_NO_01.equals(boxMhgoods.getIsNewUser())) {
                    BigDecimal newUserPrice = boxMhgoods.getNewUserPrice() != null ? boxMhgoods.getNewUserPrice() : BigDecimal.valueOf(0);
                    //除掉首单新人价的总价
                    BigDecimal total = BigDecimal.valueOf(cartSkuVO.getNum() - 1).multiply(BigDecimal.valueOf(cartSkuVO.getGoodsSku().getPrice()));
                    //首单价 + 除去首单的总价  = 方案购买价
                    cartSkuVO.getPriceDetailDTO().setGoodsPrice(newUserPrice.add(total).doubleValue());
                    continue;
                }
            }
            if (null != cartSkuVO.getPromotionTypeEnum() && (PromotionTypeEnum.PINTUAN.name().equals(cartSkuVO.getPromotionTypeEnum().name()) ||
                    PromotionTypeEnum.SECKILL.name().equals(cartSkuVO.getPromotionTypeEnum().name()))) {
                cartSkuVO.getPriceDetailDTO().setGoodsPrice(CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(), cartSkuVO.getNum()));
            }else {
                cartSkuVO.getPriceDetailDTO().setGoodsPrice(CurrencyUtil.mul(GoodsSkuPriceUtil.getPrice(cartSkuVO.getGoodsSku(),tradeDTO), cartSkuVO.getNum()));
            }
        }

        tradeDTO.getSkuList().forEach(cartSkuVO -> cartSkuVO.getPriceDetailDTO().setOriginalPrice(CurrencyUtil.mul(cartSkuVO.getGoodsSku().getPrice(),
                cartSkuVO.getNum())));

        Double goodsMaxReturnActivityPrice = tradeDTO.getSkuList().stream()
                .filter(cartSkuVO -> null != cartSkuVO.getIsGreenSecurities() && cartSkuVO.getIsGreenSecurities())
                .mapToDouble(sku -> CurrencyUtil.mul(sku.getIsGreenSecuritiesPrice(), sku.getNum())).sum();
        tradeDTO.setGoodsMaxReturnActivityPrice(goodsMaxReturnActivityPrice);

    }

    /**
     * 校验商品属性
     *
     * @param tradeDTO 购物车视图
     */
    private void checkData(TradeDTO tradeDTO) {
        //循环购物车中的商品
        for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) {

            //如果失效，确认sku为未选中状态
            if (Boolean.TRUE.equals(cartSkuVO.getInvalid())) {
                //设置购物车未选中
                cartSkuVO.setChecked(false);
            }

            //缓存中的商品信息
            GoodsSku dataSku = goodsClient.getGoodsSkuByIdFromCache(cartSkuVO.getGoodsSku().getId());

            //商品上架状态判定
            boolean checkGoodsStatus =
                    dataSku == null || !GoodsAuthEnum.PASS.name().equals(dataSku.getAuthFlag()) || !GoodsMarketEnum.UPPER.name().equals(dataSku.getMarketEnable());
            //商品有效性判定
            boolean checkGoodsValid =
                    dataSku != null && dataSku.getUpdateTime() != null && cartSkuVO.getGoodsSku().getUpdateTime() != null && dataSku.getUpdateTime().after(cartSkuVO.getGoodsSku().getUpdateTime());

            // 获取商品最新促销信息
            if (!checkGoodsStatus) {
                CartSkuVO currentGoodsPromotion = promotionGoodsClient.getCurrentGoodsPromotion(cartSkuVO);
                if (currentGoodsPromotion != null && CollUtil.isNotEmpty(currentGoodsPromotion.getPromotionMap())) {
                    cartSkuVO.setPromotionMap(currentGoodsPromotion.getPromotionMap());
                    cartSkuVO.getGoodsSku().setPromotionFlag(currentGoodsPromotion.getGoodsSku().getPromotionFlag());
                    cartSkuVO.getGoodsSku().setPromotionPrice(currentGoodsPromotion.getGoodsSku().getPromotionPrice());
                }
            }

            if ((checkGoodsStatus || checkGoodsValid)) {
                if (checkGoodsValid) {
                    CartSkuVO newCartSkuVO = new CartSkuVO(dataSku);
                    newCartSkuVO.setCartType(tradeDTO.getCartSceneEnum());
                    newCartSkuVO.setNum(cartSkuVO.getNum());
                    newCartSkuVO.setSubTotal(CurrencyUtil.mul(newCartSkuVO.getPurchasePrice(), cartSkuVO.getNum()));
                    newCartSkuVO.setPromotionMap(cartSkuVO.getPromotionMap());
                    Boolean checked = cartSkuVO.getChecked();
                    BeanUtils.copyProperties(newCartSkuVO, cartSkuVO, "priceDetailDTO", "priceDetailVO");
                    cartSkuVO.setChecked(checked);
                    log.info("商品信息已更新，更新后的商品信息为：{}", cartSkuVO);
                }
                if (checkGoodsStatus) {
                    //设置购物车未选中
                    cartSkuVO.setChecked(false);
                    //设置购物车此sku商品已失效
                    cartSkuVO.setInvalid(true);
                    //设置失效消息
                    cartSkuVO.setErrorMessage("商品已下架");
                }
                continue;
            }

            //商品库存判定
            if (dataSku.getQuantity() < cartSkuVO.getNum()) {
                log.info("checkData->num:{}", cartSkuVO.getNum());
                log.info("checkData->Quantity:{}", dataSku.getQuantity());
                //设置购物车未选中
                cartSkuVO.setChecked(false);
                //设置失效消息
                cartSkuVO.setErrorMessage("商品库存不足,现有库存数量[" + dataSku.getQuantity() + "]");
            }
            //如果存在商品促销活动，则判定商品促销状态
            if (!PromotionTypeEnum.POINTS_GOODS.equals(cartSkuVO.getPromotionTypeEnum()) && !PromotionTypeEnum.RED_PACK_GOODS.equals(cartSkuVO.getPromotionTypeEnum())  && (CollUtil.isNotEmpty(cartSkuVO.notFilterPromotionMap()) || Boolean.TRUE.equals(cartSkuVO.getGoodsSku().getPromotionFlag()))) {
                Double goodsPrice = cartSkuVO.getGoodsSku().getPromotionFlag() != null && cartSkuVO.getGoodsSku().getPromotionFlag() ?
                        cartSkuVO.getGoodsSku().getPromotionPrice() : cartSkuVO.getGoodsSku().getPrice();
                cartSkuVO.setPurchasePrice(goodsPrice);
                cartSkuVO.setUtilPrice(goodsPrice);
                cartSkuVO.setSubTotal(CurrencyUtil.mul(cartSkuVO.getPurchasePrice(), cartSkuVO.getNum()));
            }

        }
    }

    /**
     * 店铺分组
     *
     * @param tradeDTO
     */
    private void groupStore(TradeDTO tradeDTO) {
        //渲染的购物车
        List<CartVO> cartList = new ArrayList<>();

        //根据店铺分组
        Map<String, List<CartSkuVO>> storeCollect = tradeDTO.getSkuList().stream().collect(Collectors.groupingBy(CartSkuVO::getStoreId));
        for (Map.Entry<String, List<CartSkuVO>> storeCart : storeCollect.entrySet()) {
            if (!storeCart.getValue().isEmpty()) {
                //根据销售类型再次分类
                CartVO cartVO = new CartVO(storeCart.getValue().get(0));
                if (CharSequenceUtil.isEmpty(cartVO.getDeliveryMethod())) {
                    cartVO.setDeliveryMethod(DeliveryMethodEnum.LOGISTICS.name());
                }
                cartVO.setSkuList(storeCart.getValue());

                try {
                    //筛选属于当前店铺的优惠券
                    storeCart.getValue().forEach(i -> i.getPromotionMap().forEach((key, value) -> {
                        if (key.contains(PromotionTypeEnum.COUPON.name())) {
                            JSONObject promotionsObj = JSONUtil.parseObj(value);
                            Coupon coupon = JSONUtil.toBean(promotionsObj, Coupon.class);
                            if (key.contains(PromotionTypeEnum.COUPON.name()) && coupon.getStoreId().equals(storeCart.getKey())) {
                                cartVO.getCanReceiveCoupon().add(new CouponVO(coupon));
                            }
                        }
                    }));
                } catch (Exception e) {
                    log.error("筛选属于当前店铺的优惠券发生异常！", e);
                }
                storeCart.getValue().stream().filter(i -> Boolean.TRUE.equals(i.getChecked())).findFirst().ifPresent(cartSkuVO -> cartVO.setChecked(true));
                cartList.add(cartVO);
            }
        }
        tradeDTO.setCartList(cartList);
    }

    /**
     * 订单预校验
     * 1、自己拼团自己创建都拼团判定、拼团限购
     * 2、积分购买，积分足够与否
     *
     * @param tradeDTO 交易
     */
    private void preCalibration(TradeDTO tradeDTO) {
        //拼团订单预校验
        if (PromotionTypeEnum.PINTUAN.equals(tradeDTO.getPromotionType())) {
            //拼团判定，不能参与自己创建的拼团
            if (tradeDTO.getParentOrderSn() != null) {
                //订单接收
                Order parentOrder = orderService.getBySnNoAuth(tradeDTO.getParentOrderSn());
                //参与活动判定
                if (parentOrder.getBuyerId().equals(UserContext.getCurrentUser().getExtendId())) {
                    throw new ServiceException(ResultCode.PINTUAN_JOIN_ERROR);
                }
            }
            //判断拼团商品的限购数量
            if (tradeDTO.getSkuList().get(0).getPromotionMap() != null && !tradeDTO.getSkuList().get(0).getPromotionMap().isEmpty()) {
                Optional<Map.Entry<String, Object>> pintuanPromotions =
                        tradeDTO.getSkuList().get(0).getPromotionMap().entrySet().stream().filter(i -> i.getKey().contains(PromotionTypeEnum.PINTUAN.name())).findFirst();
                if (pintuanPromotions.isPresent()) {
                    JSONObject promotionsObj = JSONUtil.parseObj(pintuanPromotions.get().getValue());
                    Pintuan pintuan = promotionsObj.toBean(Pintuan.class);
                    Integer limitNum = pintuan.getLimitNum();
                    for (CartSkuVO cartSkuVO : tradeDTO.getSkuList()) {
                        if (limitNum != 0 && cartSkuVO.getNum() > limitNum) {
                            throw new ServiceException(ResultCode.PINTUAN_LIMIT_NUM_ERROR);
                        }
                    }
                }
            }
            //积分商品，判断用户积分是否满足
        } else if (PromotionTypeEnum.POINTS_GOODS.equals(tradeDTO.getPromotionType())
                && tradeDTO.getSkuList().get(0).getPromotionMap() != null
                && !tradeDTO.getSkuList().get(0).getPromotionMap().isEmpty()) {
            //获取积分商品VO
            Optional<Map.Entry<String, Object>> pointsPromotions =
                    tradeDTO.getSkuList().get(0).getPromotionMap().entrySet().stream().filter(i -> i.getKey().contains(PromotionTypeEnum.POINTS_GOODS.name())).findFirst();
            if (pointsPromotions.isPresent()) {
                JSONObject promotionsObj = JSONUtil.parseObj(pointsPromotions.get().getValue());
                PointsGoods pointsGoods = promotionsObj.toBean(PointsGoods.class);
                if (pointsGoods == null) {
                    throw new ServiceException(ResultCode.POINT_GOODS_ERROR);
                }
                if (walletPointClient.getUserPoint(tradeDTO.getMemberId()) < pointsGoods.getPoints()) {
                    throw new ServiceException(ResultCode.USER_POINTS_ERROR);
                }
            }

        }else if (PromotionTypeEnum.RED_PACK_GOODS.equals(tradeDTO.getPromotionType())
                && tradeDTO.getSkuList().get(0).getPromotionMap() != null
                && !tradeDTO.getSkuList().get(0).getPromotionMap().isEmpty()) {
            //获取红包商品VO
            Optional<Map.Entry<String, Object>> pointsPromotions =
                    tradeDTO.getSkuList().get(0).getPromotionMap().entrySet().stream().filter(i -> i.getKey().contains(PromotionTypeEnum.RED_PACK_GOODS.name())).findFirst();
            if (pointsPromotions.isPresent()) {
                JSONObject promotionsObj = JSONUtil.parseObj(pointsPromotions.get().getValue());
                RedPackGoods redPackGoods = promotionsObj.toBean(RedPackGoods.class);
                if (redPackGoods == null) {
                    throw new ServiceException(ResultCode.RED_PACK_GOODS_ERROR);
                }
                RedPackUser redPackUser = redPackUserClient.getRedPackUser(tradeDTO.getMemberId());
                if (null == redPackUser || 0 == redPackUser.getStatus()) {
                    throw new ServiceException(ResultCode.USER_RED_PACK_ERROR);
                }
                if (redPackUser.getRedPackCount() < redPackGoods.getRedPack()) {
                    throw new ServiceException(ResultCode.USER_RED_PACK_COUNT_ERROR);
                }
            }

        }

    }


    /**
     * 商品销售模式特殊处理
     *
     * @param tradeDTO 交易信息
     */
    private void preSaleModel(TradeDTO tradeDTO) {
        // 寻找同goods下销售模式为批发的商品
        Map<String, List<CartSkuVO>> goodsGroup =
                tradeDTO.getSkuList().stream().filter(i -> i.getGoodsSku().getSalesModel().equals(SalesModeEnum.WHOLESALE.name())).collect(Collectors.groupingBy(i -> i.getGoodsSku().getGoodsId()));
        if (CollUtil.isNotEmpty(goodsGroup)) {
            goodsGroup.forEach((k, v) -> {
                // 获取购买总数
                int sum = v.stream().filter(i -> Boolean.TRUE.equals(i.getChecked())).mapToInt(CartSkuVO::getNum).sum();
                int fSum = v.stream().filter(i -> Boolean.FALSE.equals(i.getChecked())).mapToInt(CartSkuVO::getNum).sum();
                // 匹配符合的批发规则
                Wholesale match = goodsClient.getMatchWholesale(k, sum);
                if (match != null) {
                    if (match.getNum() > (sum + fSum)) {
                        for (CartSkuVO cartSkuVO : v) {
                            //设置购物车未选中
                            cartSkuVO.setChecked(false);
                            //设置失效消息
                            cartSkuVO.setErrorMessage("购买数量不足批量商品的起批量,起批量[" + match.getNum() + "]");
                        }
                    }
                    v.forEach(i -> {
                        // 将符合规则的商品设置批发价格
                        if (Boolean.TRUE.equals(i.getChecked())) {
                            i.setPurchasePrice(match.getPrice());
                            i.getGoodsSku().setPrice(match.getPrice());
                            i.getGoodsSku().setCost(match.getPrice());
                            i.setUtilPrice(match.getPrice());
                            i.setSubTotal(CurrencyUtil.mul(i.getPurchasePrice(), i.getNum()));
                        } else {
                            i.setPurchasePrice(goodsClient.getMatchWholesale(k, fSum).getPrice());
                            i.getGoodsSku().setPrice(i.getPurchasePrice());
                            i.getGoodsSku().setCost(i.getPurchasePrice());
                            i.setUtilPrice(i.getPurchasePrice());
                            i.setSubTotal(CurrencyUtil.mul(i.getPurchasePrice(), i.getNum()));
                        }
                    });
                }
            });
        }
    }

    public void setCategoryInformation(TradeDTO tradeDTO) {
        Iterator<CartSkuVO> iterator = tradeDTO.getSkuList().iterator();
        while (iterator.hasNext()) {
            CartSkuVO cartSkuVO = iterator.next();
            PriceDetailDTO priceDetailDTO = cartSkuVO.getPriceDetailDTO();
            String categoryId = cartSkuVO.getGoodsSku().getCategoryPath()
                    .substring(cartSkuVO.getGoodsSku().getCategoryPath().lastIndexOf(",") + 1);
            if (CharSequenceUtil.isNotEmpty(categoryId)) {
                Category category = categoryClient.getById(categoryId);
                Double commissionRate = category == null ? 0 : category.getCommissionRate();
                priceDetailDTO.setStoreCommissionPoint(CurrencyUtil.div(commissionRate, 100));
                priceDetailDTO.setSupplierCommissionPoint(CurrencyUtil.div(commissionRate, 100));
            }
        }
    }

}
